const puppeteer = require("puppeteer-core");
const readline = require("readline");
const chalk = require('chalk');
const info = function (t) {
    console.log(chalk.bold.green(t));
};
require('events').EventEmitter.defaultMaxListeners = 99999;
//创建交互流
const rl = readline.createInterface({input: process.stdin, output: process.stdout});

class WaitUtil {
    constructor() {
        this.page = null;
    }

    waitPageLoad() {
        return new Promise(r => this.page.once("load", r))
    }

    waitForAWhile() {
        return new Promise((resolve) => {
            setTimeout(resolve, 300)
        });
    }

    waitFor100ms() {
        return new Promise((resolve) => {
            setTimeout(resolve, 100)
        });
    }

    waitRequest() {
        return new Promise((resolve) => {
            this.page.on('request', resolve)
        });
    }
}

class Grab extends WaitUtil {
    constructor() {
        super();
        this.browser = null;
        this.page = null;
        this.headless = false;
        this.targetUrl = "https://www.mi.com/";
        this.account = "13260689710";
        this.password = "wo131421";
        this.productUrl = "http://item.mi.com/product/10000131.html";
        this.qrCode = "./screen.png";
    }

    /***
     * 初始化puppeteer
     */
    async init() {
        this.browser = await puppeteer.launch({
            headless: this.headless, executablePath: `D:\\chromev75.0.3733.0\\chrome.exe`,
            defaultViewport: {
                width: 1920, height: 1080
            }
        });
    }

    /***
     * 打开页面
     */
    async openPage() {
        this.page = await this.browser.newPage();
        await this.page.goto(this.targetUrl);
    }

    /***
     * 前往登录
     */
    async gotoLoginPage() {
        const loginDom = await this.page.$(`.link[data-login="true"]`);
        await loginDom.click();
        let isShowDialog = false;
        //等待弹窗出现
        while (!isShowDialog) {
            isShowDialog = (await this.page.$eval(`#J_agreeModal`, (node) => node.style.display)) === "block"
        }
        //获取弹窗
        let dialogDom = await this.page.$(`.btn.btn-primary.J_sure`);
        await dialogDom.click();
    }

    /***
     * 登录
     */
    async login() {
        await this.waitPageLoad();
        const {page, account, password} = this;
        await (await page.$(`#username`)).type(account);
        await (await page.$(`#pwd`)).type(password);
        await (await page.$(`#login-button`)).click();
        await this.waitForAWhile();
        /***          验证码处理          ****/
        await page.screenshot({path: this.qrCode});
        info("已截图");
        const qrText = await new Promise((resolve) => {
            rl.question("请输入验证码\r\n", resolve);
        });
        info(`输入的验证码为：${qrText}`);
        await (await page.$(`#captcha-code`)).type(qrText);

        await (await page.$(`#login-button`)).click();
    }


    /***
     * 前往手机页面
     */
    async gotoBuyPage(p, callback) {
        await this.waitPageLoad();
        const {page} = this;
        const recursiveFn = () => {
            info("验证成功");
            p.then(() => {
                return page.goto(this.productUrl);
            }).then(() => {
                info("进入购买页");
                return this.waitForAWhile();
            }).then(() => {
                return page.$(`.btn.btn-primary.btn-biglarge.J_proBuyBtn`);
            }).then(async (payBtn) => {
                if (!payBtn) {
                    recursiveFn();
                } else {
                    const lowTypeBtn = await page.$(`#J_list > div:nth-child(1) > ul > li:nth-child(4)`);
                    await lowTypeBtn.click();
                    await this.waitRequest();
                    const blackBtn = await page.$(`#J_list > div:nth-child(2) > ul > li:nth-child(3)`);
                    await blackBtn.click();
                    await this.waitRequest();
                    await this.waitForAWhile();
                    //由于选择了新规格 需要重新获取购买dom节点
                    const newPayBtn = await page.$(`.btn.btn-primary.btn-biglarge.J_proBuyBtn`);
                    return newPayBtn.click().then(callback);
                }
            })
        };
        recursiveFn();
    }

    /***
     * 进入购物车页面
     */
    async gotoShoppingCert() {
        await this.waitPageLoad();
        info("进入购物车");
        const {page} = this;
        await this.waitFor100ms();
        await (await page.$(`div.actions.J_actBox > a.btn.btn-primary`)).click();
    }

    /***
     * 进入购物车结算成功页面
     */
    async gotoSettle() {
        await this.waitPageLoad();
        const {page} = this;
        info("进入购物车结算");
        await (await page.$(`#J_goCheckout`)).click();
    }

    /***
     * 提交订单
     */
    async gotoCheckBill() {
        await this.waitPageLoad();
        const {page} = this;
        info("进入结算页面");
        // await awaitRequest(); //此处不确定是否需要等待
        await (await page.$(`#J_addressList > div.address-item.J_addressItem`)).click();
        await (await page.$(`#J_checkoutToPay`)).click();
    }


}


(async () => {
    const instance = new Grab();
    await instance.init();
    await instance.openPage();
    await instance.gotoLoginPage();
    await instance.login();
    const p = Promise.resolve();
    await instance.gotoBuyPage(p, async () => {
        info("开始下单");
        await instance.gotoShoppingCert();
        await instance.gotoSettle();
        await instance.gotoCheckBill();
        info("下单完毕");
    });
})();
